package com.achen.elasticsearch.dao.impl;

import com.achen.elasticsearch.dao.CustomerProductRepository;
import com.achen.elasticsearch.entity.Product;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author achen
 * @create 2020-04-29 21:40
 */
@Repository
public class CustomerProductRepositoryImpl implements CustomerProductRepository {

    private static Logger logger = LoggerFactory.getLogger(CustomerProductRepositoryImpl.class);

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Override
    public List<Product> findContentTermQuery(String contentkeyword) {
        SearchQuery searchQuery = new NativeSearchQuery(QueryBuilders.termQuery("content", contentkeyword));
        List<Product> products = elasticsearchTemplate.queryForList(searchQuery, Product.class);
        return products;
    }

    @Override
    public List<Product> findContentTermQuerySourceField(String contentkeyword, String... str) {
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                .withIndices("dangdang") //指定索引
                .withTypes("product") //指定类型
                .withQuery(QueryBuilders.termQuery("content", contentkeyword)) //指定查询条件
                .withFields(str) //指定返回字段
                .build();
        List<Product> products = elasticsearchTemplate.queryForList(nativeSearchQuery, Product.class);
        return products;
    }

    @Override
    public List<Product> findContentTermQuerySourceFieldPageable(Integer page, Integer size, String contentkeyword, String... str) {
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().
                withQuery(QueryBuilders.termQuery("content", contentkeyword))
                .withFields(str)
                .withPageable(PageRequest.of(page, size))
                .build();
        return elasticsearchTemplate.queryForList(nativeSearchQuery, Product.class);
    }

    @Override
    public List<Product> findContentTermQuerySourceFieldPageableSort(String sortField, Integer page, Integer size, String contentkeyword, String... str) {
        //创建sortBuilder对象
        SortBuilder sortBuilder = SortBuilders.fieldSort(sortField).order(SortOrder.ASC);
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.termQuery("content", contentkeyword))
                .withPageable(PageRequest.of(page, size))
                .withFields(str)
                .withSort(sortBuilder)
                .build();
        return elasticsearchTemplate.queryForList(nativeSearchQuery, Product.class);
    }

    @Override
    public List<Product> findContentTermQuerySourceFieldPageableSortFilter(String filterField, String filterkeyword, String sortField, Integer page, Integer size, String contentkeyword, String... str) {
        //创建sortBuilder对象
        FieldSortBuilder sortBuilder = SortBuilders.fieldSort(sortField).order(SortOrder.DESC);
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.termQuery("content", contentkeyword))
                .withPageable(PageRequest.of(page, size))
                .withSort(sortBuilder)
                .withFields(str)
                .withFilter(QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery(filterField, filterkeyword))) //加入过滤条件
                .build();
        return elasticsearchTemplate.queryForList(nativeSearchQuery, Product.class);
    }

    @Override
    public List<Product> findProductHeight(String querykeyword, Integer page, Integer size, String... str) {
        //创建高亮字段
        HighlightBuilder.Field field = new HighlightBuilder.Field("*")
                .preTags("<span style='color:red'>") //样式
                .postTags("</span>")
                .requireFieldMatch(false); //多字段高亮
        //创建sortBuilder对象
        FieldSortBuilder sortBuilder = SortBuilders.fieldSort("price").order(SortOrder.ASC);
        //创建检索对象
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                .withFilter(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("price").lte(100))) //过滤条件：价格<=100
                .withQuery(QueryBuilders.queryStringQuery(querykeyword).analyzer("ik_max_word").field("name").field("content")) //多字段查询
                .withPageable(PageRequest.of(page, size)) //分页
                .withSort(sortBuilder) //排序
                .withFields(str) //返回指定字段
                .withHighlightFields(field) //处理高亮显示
                .build();
        AggregatedPage<Product> products = elasticsearchTemplate.queryForPage(nativeSearchQuery, Product.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                //创建集合存取product
                List<Product> productList = new ArrayList<>();
                //得到Hits集合
                SearchHit[] hits = searchResponse.getHits().getHits();
                logger.warn(searchResponse.getHits().toString());
                for (SearchHit hit : hits) {
                    /*System.out.println(hit);
                    System.out.println(hit.getHighlightFields());*/
                    Product product = new Product();
                    //获取map
                    Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                    //判断是否包含该字段
                    String id = sourceAsMap.containsKey("id") ? sourceAsMap.get("id").toString() : "";
                    String name = sourceAsMap.containsKey("name") ? sourceAsMap.get("name").toString() : "";
                    Double price = sourceAsMap.containsKey("price") ? Double.valueOf(sourceAsMap.get("price").toString()) : 0.0;
                    String author = sourceAsMap.containsKey("author") ? sourceAsMap.get("author").toString() : "";
                    String content = sourceAsMap.containsKey("content") ? sourceAsMap.get("content").toString() : "";
                    Date createDate = sourceAsMap.containsKey("createDate") ? new Date(Long.valueOf(sourceAsMap.get("createDate").toString())) : null;

                    //给product赋值
                    product.setId(id);
                    product.setName(name);
                    product.setPrice(price);
                    product.setAuthor(author);
                    product.setContent(content);
                    product.setCreateDate(createDate);

                    //获取当前文档高亮字段map集合
                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    //name高亮显示，判断是否有name
                    if (!StringUtils.isEmpty(name)) {
                        if (highlightFields.get("name") != null) {
                            String heightName = highlightFields.get("name").getFragments()[0].toString();
                            product.setName(heightName);
                        }
                    }
                    //content高亮显示，判断是否有content
                    if (!StringUtils.isEmpty(content)) {
                        if (highlightFields.get("content") != null) {
                            String heightContent = highlightFields.get("content").getFragments()[0].toString();
                            product.setContent(heightContent);
                        }
                    }
                    productList.add(product);
                }
                return new AggregatedPageImpl<>((List<T>) productList);
            }
        });
        return products.getContent();
    }
}
